/*
Package common
author: jamon
time: 2023-09-05
desc:
*/
package common

import (
	"fmt"
	"gitee.com/jamon/espoir_go/logger"
	"runtime"
	"sync"
	"time"
)

const stackBufCap = 4096
const retryDelay = 1 * time.Second

func RecoverPanic(recovered interface{}) bool {
	if recovered != nil {
		buf := make([]byte, stackBufCap)
		n := runtime.Stack(buf, false)
		tip := fmt.Sprint(recovered)
		logger.Error(tip, logger.Kwargs{"stacktrace": string(buf[:n])})
		return true
	}
	return false
}

func SafeRun(f func()) {
	defer func() {
		RecoverPanic(recover())
	}()
	f()
}

func SafeRunWithRetry(f func()) {
	defer func() {
		if RecoverPanic(recover()) {
			time.Sleep(retryDelay) // 防止无限重试日志刷爆磁盘
			go SafeRunWithRetry(f)
		}
	}()
	f()
}

// SafeGoWithWaitGroup 注意: 不用go这个方法; 在循环中使用时注意局部变量的捕获!
func SafeGoWithWaitGroup(f func(), wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer func() {
			RecoverPanic(recover())
			wg.Done()
		}()
		f()
	}()
}

// SafeGoWithWaitGroupWithRetry 注意: 不用go这个方法; 在循环中使用时注意局部变量的捕获!
func SafeGoWithWaitGroupWithRetry(f func(), wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer func() {
			if RecoverPanic(recover()) {
				time.Sleep(retryDelay) // 防止无限重试日志刷爆磁盘
				SafeGoWithWaitGroupWithRetry(f, wg)
			}
			wg.Done()
		}()
		f()
	}()
}
